# -*- coding: utf-8 -*-
import json
import logging
from decimal import Decimal

from sqlalchemy import func, text

from common import orm
from common.pay.model import PAY_STATUS, Pay, CREATED_BY_TYPE
from common.account.model.account import Account
from common.utils import id_generator, EnhencedEncoder
from common.utils.decorator import sql_wrapper
from common.utils.db import (generate_filter, parse_query_dct,
                             get_orderby, paginate, get_count)

from common.utils.tz import *

_LOGGER = logging.getLogger(__name__)

USER_TYPE = {
    'new_user': 1,
    'next_day_user': 2,
    'week_user': 3,
    'old_user': 4,
}

USER_TYPE_TEXT = {
    '1': u'新用户',
    '2': u'次日用户',
    '3': u'周用户',
    '4': u'老用户'
}

PAY_TYPE_TEXT = {
    '2': u'支付宝',
    '3': u'微信',
    '4': u'银联支付',
    '5': 'jingdong',
    '6': 'baidu wallet',
    '7': u'爱贝支付',
    '8': u'支付宝WAP',
    '9': 'wii pay',
    '10': u'友信',
    '11': u'爱贝WAP',
    '12': u'即刻支付WAP',
    '13': 'swift',
    '14': 'shenfutong',
    '15': u'爱贝马甲',
    '17': u'高阳',
    '18': 'swiftpass alipay',
    '19': 'paypayfu alipay',
    '20': 'juhefu alipay',
    '21': 'mingtianyun alipay',
    '22': 'mingtianyun weixin',
    '23': 'swiftpass weixin',
    '24': u"聚合富 支付宝(新)",
    '25': u"聚合富 支付宝wap(新)",
    '26': u"威腾 微信wap",
    '27': u"聚合富 微信扫码",
    '28': u"掌支付支付宝SDK",
    '30': u"天宏在线微信SDK",
    '31': u"天宏在线支付宝WAP",
    '32': u"融梦微信支付SDK",
    '100': u"微信公众号支付",
    '103': u'微信代理',
    '1000': u"内部聚合支付微信",
    '1001': u"内部聚合支付支付宝",
    '1002': u"内部聚合支付银联",
    '1011': u'定额支付宝',
    '1012': u"内部聚合支付qq",
    '1013': u"内部聚合支付jd",
    '1014': u"unionagency_v1",
    '1015': u"unionagency_v2支付宝",
    '1016': u"unionagency_v2银行卡",
    '1017': u"unionagency_v2微信",
    '1111': u"内部聚合支付测试通道",
}


@sql_wrapper
def get_pay(pay_id):
    return Pay.query.filter(Pay.id == pay_id).first()


@sql_wrapper
def get_last_pay_by_user_id(user_id, pay_status=None, pay_type=None):
    pay = Pay.query.filter(Pay.user_id == user_id)
    if pay_status:
        if not isinstance(pay_status, list):
            pay_status = [pay_status]
        pay = pay.filter(Pay.status.in_(pay_status))

    if pay_type:
        if not isinstance(pay_type, list):
            pay_type = [pay_type]
        pay = pay.filter(Pay.pay_type.in_(pay_type))

    pay = pay.order_by(Pay.created_at.desc()).first()

    if not pay:
        return None
    return pay.as_dict()


@sql_wrapper
def get_pay_record_by_user_id(user_id, limit=20, offset=0):
    pay = Pay.query.filter(Pay.user_id == user_id).order_by(Pay.created_at.desc())
    total = get_count(pay)
    pay = pay.offset(offset).limit(limit)
    return [p.as_dict() for p in pay.all()], total


@sql_wrapper
def list_pay(query_dct):
    user_type = int(query_dct.pop('user_type', 0))
    query_dct = parse_query_dct(query_dct, Pay)
    query = orm.session.query(Pay, Account.created_at.label('ac_t')).join(
        Account, Account.id == Pay.user_id)
    if user_type:
        if user_type == 1:
            query = query.filter(func.DATE(func.DATE_ADD(Account.created_at, text('interval 8 hour'))) ==
                                 func.DATE(func.DATE_ADD(Pay.created_at, text('interval 8 hour'))))
        elif user_type == 2:
            query = query.filter(func.DATE(func.DATE_ADD(Account.created_at, text('interval 32 hour'))) ==
                                 func.DATE(func.DATE_ADD(Pay.created_at, text('interval 8 hour'))))
        elif user_type == 3:
            query = query.filter(func.DATE(func.DATE_ADD(Account.created_at, text('interval 32 hour'))) <
                                 func.DATE(func.DATE_ADD(Pay.created_at, text('interval 8 hour'))),
                                 func.DATE(func.DATE_ADD(Account.created_at, text('interval 176 hour'))) >
                                 func.DATE(func.DATE_ADD(Pay.created_at, text('interval 8 hour'))))
        else:
            query = query.filter(func.DATE(func.DATE_ADD(Account.created_at, text('interval 176 hour'))) <=
                                 func.DATE(func.DATE_ADD(Pay.created_at, text('interval 8 hour'))))
    query = query.filter(generate_filter(query_dct, Pay))
    total_count = get_count(query)
    if '$orderby' in query_dct:
        query = query.order_by(get_orderby(query_dct['$orderby'], Pay))
    query = paginate(query, query_dct)

    return query.all(), total_count


@sql_wrapper
def get_pay_overview(parsed_dct):
    query = orm.session.query(Pay.pay_type, func.count(Pay.id),
                              func.sum(Pay.price), Pay.created_by)
    query = query.filter(generate_filter(parsed_dct, Pay))
    if 'pay_type' not in parsed_dct:
        query = query.group_by(Pay.pay_type, Pay.created_by)
    resp = []
    for r in query.all():
        # (type, count , sum)
        resp.append({
            "pay_type": r[0] or parsed_dct.get('pay_type', 0),
            "count": r[1],
            "total": float(r[2]) if r[2] is not None else 0,
            "created_by": r[3],
        })
    return resp


@sql_wrapper
def create_pay(user_id, pay_type, created_by=CREATED_BY_TYPE.USER):
    # Pay.query.filter(Pay.user_id == user_id)\
    #         .filter(Pay.pay_type == pay_type)\
    #         .filter(Pay.status == PAY_STATUS.WAIT)\
    #         .delete()
    pay = Pay()
    pay.id = id_generator.generate_long_id('pay')
    pay.user_id = user_id
    pay.pay_type = pay_type
    pay.status = PAY_STATUS.WAIT
    pay.created_by = created_by
    pay.save()
    return pay


@sql_wrapper
def fill_pay(pay_id, pay_amount, content):
    pay = Pay.query.with_for_update().filter(
        Pay.id == pay_id).one()
    pay.price = Decimal(pay_amount)
    if content:
        extend = json.loads(pay.extend or '{}')
        extend.update(content)
        pay.extend = json.dumps(
            extend, cls=EnhencedEncoder, ensure_ascii=False)
    pay.save()


@sql_wrapper
def update_pay_ext(pay_id, ext):
    pay = Pay.query.with_for_update().filter(Pay.id == pay_id).first()
    extend = {} if not pay.extend else json.loads(pay.extend)
    extend.update(ext)
    pay.extend = json.dumps(extend, ensure_ascii=False)
    pay.save()


@sql_wrapper
def submit_pay_commit(pay_id, user_id):
    res = Pay.query.filter(Pay.id == pay_id).filter(
        Pay.user_id == user_id).filter(
        Pay.status == PAY_STATUS.WAIT).update(
        {'status': PAY_STATUS.SUBMIT})
    orm.session.commit()
    if res:
        return Pay.query.filter(Pay.id == pay_id).one()
    return None


@sql_wrapper
def submit_pay_revert(pay_id):
    Pay.query.filter(Pay.id == pay_id) \
        .filter(Pay.status == PAY_STATUS.SUBMIT).update(
        {'status': PAY_STATUS.WAIT})
    orm.session.commit()


def get_today_recharge(user_id, exclude_pay_type):
    return orm.session.query(func.sum(Pay.price)).filter(Pay.user_id == user_id,
                                                         Pay.status == PAY_STATUS.DONE).filter(
        Pay.updated_at > get_utc_date()).filter(Pay.pay_type.notin_(exclude_pay_type)).first()[0] or 0
